home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
c
/
cserial.zip
/
8250XON.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-04
|
13KB
|
494 lines
/*
* 8250XON.C
*
* NSC8250 RS232 Xon/Xoff ISR Routine
*
* Written for the
*
* Datalight
* Microsoft V 5.x
* TurboC
* &
* Zortech
*
* C Compilers
*
* Copyright (c) John Birchfield 1987, 1988, 1989
*/
#include <stdio.h>
#include "dependnt.h"
#include "delay.h"
#include "8250nsc.h"
#include "8250xon.h"
#include "queue.h"
#include "timer.h"
#if (!defined (TRUE))
# define TRUE (1)
# define FALSE (0)
#endif
#define I_BUF_SIZE 4096 /* inbyteut Buffer Size */
#define O_BUF_SIZE 4096 /* output Buffer Size */
volatile unsigned XON_PORT_address = 0x03F8;
volatile char xoff_enabled = FALSE,
xoff_sent = FALSE,
xoff_received = FALSE,
XON_PORT_status = 0,
XON_PORT_state = 0,
XON_PORT_command = 0,
XON_char = 0x11,
XOFF_char = 0x13;
char XON_PORT_channel = 1,
SAVE_int_mask = 0, /* saved interrupt controller mask word */
/*
* 8250 register save locations and base address offsets
*/
IER_save = 0, LCR_save = 0, MCR_save = 0, DL_lsb = 0, DL_msb = 0;
QUEUE *xon8250_inqueue, *xon8250_outqueue;
/*
* XON8250_ISR - This is the interrupt handler for the
* National Semiconducter 8250 Serial Chip.
* After installation by Catch_Rt, it catches the
* 8250 interrupts and en_queues incoming characters
* from the Serial Port - and de-queues outgoing
* characters to the Serial Port. The original code
* was written in assembler and provided about 80%
* of the Port's Bandwidth at 9600 baud running
* An Xmodem protocol. We'll see what this does...
*/
#if (!defined (DLC))
void (interrupt far * xon_save_vec) (void);
void interrupt far
xon8250_isr (void)
#else
int
xon8250_isr ()
#endif
{
int ch;
char test_status;
enable ();
test_status = inbyte ((XON_PORT_address + IIR));
do
{
switch (test_status)
{
case IIR_rls:
XON_PORT_status |= inbyte ((XON_PORT_address + LSR));
break;
case IIR_receive:
ch = inbyte (XON_PORT_address);
if ((xoff_enabled && !xoff_sent) &&
(ch == XOFF_char))
{
xoff_received = TRUE;
}
else
if (xoff_received &&
(ch == XON_char))
{
xoff_received = FALSE;
outbyte (XON_PORT_address + IER, XON_PORT_command = RX_TX_enable);
}
else
if ((en_queue (xon8250_inqueue, ch) < 10) &&
xoff_enabled && !xoff_sent && !xoff_received)
{
xoff_sent = TRUE;
while ((inbyte ((XON_PORT_address + LSR)) & 0x20) == 0)
;
outbyte (XON_PORT_address + IER, XON_PORT_command = RX_TX_enable);
outbyte (XON_PORT_address, XOFF_char);
}
break;
case IIR_transmit:
if (xoff_sent && (queue_avail (xon8250_inqueue) > 20))
{
xoff_sent = FALSE;
outbyte (XON_PORT_address, XON_char);
}
else
if (xoff_received)
outbyte (XON_PORT_address + IER, XON_PORT_command = RX_enable);
else
if ((ch = de_queue (xon8250_outqueue)) != -1)
{
outbyte (XON_PORT_address, ch);
}
else
{
outbyte (XON_PORT_address + IER, XON_PORT_command = RX_enable);
}
break;
case IIR_mstatus:
test_status = inbyte ((XON_PORT_address + MSR));
break;
}
} while ((test_status = inbyte (XON_PORT_address + IIR)) != IIR_complete);
disable ();
outbyte (INT_cntrl, EOI_word);
#if (defined (DLC))
return (1);
#endif
}
/*
* XON8250_INIT - Here we get the address of the 8250 Port
* which corresponds to the channel passed in.
* We then massage the 8259 Interrupt Controller
* calculate the Physical Interrupt and save off
* the 8250's current contents. Then attach the
* xon8250_isr routine to the interrupt and
* return the rt returned index for saving - it's
* needed to terminate the interrupt.
*/
#define XON8250_STACK_SIZE 512
int xon8250_intno;
static int xon_intmask [] = { 0xef, 0xf7, 0xef, 0xf7 };
/*
* The above 8259 mask bits are determined from the formula
* mask = ~(1 << (5 - PORT_CHANNEL));
* The array assumes that COM3 and COM4 use the same interrupts
* as COM1 and COM2.
*/
static int xon_intno [] = { 12, 11, 12, 11 };
/*
* The above interrupt number array is based on the algorithm
* xon8250_intno = (13 - PORT_channel);
*/
int
xon8250_init (int channel, int buffer_size)
{
int Dos_address, mask;
XON_PORT_channel = channel;
xon8250_inqueue = alloc_queue (buffer_size);
xon8250_outqueue = alloc_queue (buffer_size);
Dos_address = (XON_PORT_channel - 1) * 2;
peekmem (0x40, Dos_address, XON_PORT_address);
mask = xon_intmask [XON_PORT_channel-1];
SAVE_int_mask = inbyte (INT_mask);
mask &= SAVE_int_mask;
xon8250_intno = xon_intno [XON_PORT_channel-1];
LCR_save = inbyte (XON_PORT_address + LCR);
disable ();
outbyte (XON_PORT_address + LCR, LCR_save | LCR_DLAB);
MCR_save = inbyte (XON_PORT_address + MCR);
DL_lsb = inbyte (XON_PORT_address);
DL_msb = inbyte (XON_PORT_address + 1);
outbyte (XON_PORT_address + LCR, LCR_save & 0x7F);
IER_save = inbyte (XON_PORT_address + IER);
enable ();
#if (defined (DLC))
int_intercept (xon8250_intno, &xon8250_isr, XON8250_STACK_SIZE);
#else
xon_save_vec = getvect (xon8250_intno);
setvect (xon8250_intno, xon8250_isr);
#endif
DELAY_init ();
outbyte (INT_mask, mask);
}
/*
* XON8250_TERM - This routine restores the rs232xon 8250 back to its
* state before xon8250_INIT was called and releases the
* corresponding interrupt back to the system.
*/
void
xon8250_term (int restore)
{
disable ();
outbyte (INT_mask, SAVE_int_mask);
if (restore)
{
outbyte (XON_PORT_address + LCR, LCR_DLAB);
outbyte (XON_PORT_address, DL_lsb);
outbyte (XON_PORT_address + 1, DL_msb);
outbyte (XON_PORT_address + MCR, MCR_save);
outbyte (XON_PORT_address + LCR, 0x7F);
outbyte (XON_PORT_address + IER, IER_save);
outbyte (XON_PORT_address + LCR, LCR_save);
}
#if (defined (DLC))
int_restore (xon8250_intno);
#else
setvect (xon8250_intno, xon_save_vec);
#endif
}
/*
* XON8250_READ - this routine looks in the xon8250_inqueue for a character
*/
int
xon8250_read (void)
{
int ch;
disable ();
ch = de_queue (xon8250_inqueue);
enable ();
if ((XON_PORT_command == RX_enable) &&
((!queue_empty (xon8250_outqueue)) || xoff_sent))
outbyte (XON_PORT_address + IER, XON_PORT_command = RX_TX_enable);
return (ch);
}
/*
* XON8250_TIMED_READ - attempts to read rs232 port - if no char
* available in number of seconds passed
* returns -1
*/
int
xon8250_timed_read (i